package com.open.xbus;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.open.xbus.joor.Reflect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

/**
 *
 */
public class XBus {

    public static final String TAG = "com.open.xbus";
    public static final boolean IS_BUNDLE_DEBUG = true;

    private static XBus instance = new XBus();
    XBusAidl mXBusAidl;
    private Map<Class<?>, Class<?>> mRegisterClassMap = new HashMap<>();

    /**
     * 注册回调，用于有回调的函数处理.
     */
    private IXBusCallback mCallback = new IXBusCallback.Stub() {
        /**
         * 函数调用的时候触发此回调.
         */
        @Override
        public void callback() throws RemoteException {
        }

        /**
         * 销毁相关的回调记录.
         */
//        @Override
//        public void gc() throws RemoteException {
//        }
    };
    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mXBusAidl = XBusAidl.Stub.asInterface(service);
            Log.d(TAG, "XBus init onServiceConnected");
            // 注册回调.
            try {
                mXBusAidl.register(mCallback, Process.myPid());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "XBus init onServiceDisconnected ComponentName:" + name);
        }
    };

    public static XBus getInstance() {
        return instance;
    }

    public void init(Context context) {
        Log.d(TAG, "XBus init");
        bind(context, "", XBusService.class);
    }

    public void init(Context context, String packageName) {
        Log.d(TAG, "XBus init packageName:" + packageName);
        bind(context, packageName, XBusService.class);
    }

    public void init(Context context, Class<? extends Service> service) {
        Log.d(TAG, "XBus init service:" + service);
        bind(context, "", service);
    }

    void bind(Context context, String packageName, Class<? extends Service> service) {
        Intent intent;
        if (TextUtils.isEmpty(packageName)) {
            intent = new Intent(context, service);
        } else { // getName:com.open.xbus.XBusService
            intent = new Intent();
            intent.setClassName(packageName, service.getName());
        }
        context.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    public void disconnect(Context context) {
        unbind(context);
        Log.d(TAG, "XBus disconnect");
    }

    void unbind(Context context) {
        context.unbindService(mServiceConnection);
    }

    /**
     * 测试调用情况.
     */
    public <T> T getCreateCall(Class<T> tClass) {
        try {
            Class<?>[] interfaces = new Class[]{tClass};
            XBusHandler handler = new XBusHandler(tClass, mXBusAidl);
            Object proxy = Proxy.newProxyInstance(tClass.getClassLoader(), interfaces, handler);
            Log.d(TAG, this + " XBus getCreateCall");
            return (T) proxy;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 注册需要被调用的class.
     *
     * @param face 接口
     * @param impl 实现类
     */
    public void register(Class<?> face, Class<?> impl) {
        mRegisterClassMap.put(face, impl);
        Log.d(TAG, this + " XBus register 接口:" + face + " 类:" + impl + " size:" + mRegisterClassMap.size());
    }

    public <T> T getCreateObject(Class<?> face) {
        if (mRegisterClassMap.containsKey(face)) {
            Class<?> aClass = mRegisterClassMap.get(face);
            try {
                Log.d(TAG, this + " XBus getCreateObject className:" + aClass);
                // TODO: 处理单例的类
                // TODO: 处理静态函数
                // TODO: 避免重复创建new
                return Reflect.on(aClass).create().get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Log.d(TAG, this + " XBus getCreateObject face:" + face + " size:" + mRegisterClassMap.size());
        return null;
    }

    /**
     * 动态代理的 InvocationHandler invoke 处理.
     */
    class XBusHandler implements InvocationHandler {

        private Gson gson = new Gson();

        private Class<?> clazz;
        private XBusAidl xBusAidl;

        public XBusHandler(Class<?> clazz, XBusAidl xBusAidl) {
            this.clazz = clazz;
            this.xBusAidl = xBusAidl;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            String clazzName = clazz.getName();
            Request request = new Request();

            // 尝试获取所有参数，判断是否拥有接口.
            int length = args.length;
            for (int i = 0; i < length; ++i) {
                Class<?>[] classes = method.getParameterTypes();
                if (classes[i].isInterface()) {
                    Object parameter = args[i];
                }
            }

            if (IS_BUNDLE_DEBUG) {
                // bundle 传递 args. 方法，类名
                Bundle bundle = new Bundle();
                // bundle.putInt("args", (Integer) args[0]);
                bundle.putSerializable(Request.ARGS_KEY, args);
                bundle.putString(Request.METHOD_KEY, methodName);
                bundle.putString(Request.CLAZZ_KEY, clazzName);
                request.setBundle(bundle);
            } else {
                // 保存类名，方法，参数值. json 方式传递
                Request.ClassData classData = new Request.ClassData();
                classData.clazz = clazzName;
                classData.method = methodName;
                classData.params = null != args ? gson.toJson(args) : null;
                request.setData(gson.toJson(classData));
            }
            // 3. AIDL 远程调用 （函数执行过程)
            Response response = xBusAidl.run(request);
            // 4. 处理 返回值.
            if (IS_BUNDLE_DEBUG) {
                Bundle bundle1 = response.getBResult();
                if (null != bundle1) {
                    return bundle1.getSerializable(Response.RESULT_KEY);
                }
            }
            return gson.fromJson(response.getResult(), method.getReturnType());
        }

    }

}
